// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package time

// 睡眠暂停当前goroutine至少一段时间。
// 持续时间为负或为零会导致睡眠立即恢复。
func Sleep(d Duration)

// 与包运行时中实现的计时器的接口。
// 必须与..同步/运行时间/时间。go:
type runtimeTimer struct {
	pp       uintptr
	when     int64
	period   int64
	f        func(any, uintptr) // 注意：不能是闭包
	arg      any
	seq      uintptr
	nextwhen int64
	status   uint32
}

// when是用于设置runtimeTimer的“when”字段的帮助函数。
// 返回未来的时间，单位为纳秒，持续时间为d。
// 如果d为负，则忽略它。如果由于溢出，返回值小于
// 0，则返回MaxInt64。
func when(d Duration) int64 {
	if d <= 0 {
		return runtimeNano()
	}
	t := runtimeNano() + int64(d)
	if t < 0 {
		// N.B.runtimeNano（）和d始终为正，因此添加
		// （包括溢出）将永远不会导致t==0。
		t = 1<<63 - 1 // 数学。MaxInt64 
	}
	return t
}

func startTimer(*runtimeTimer)
func stopTimer(*runtimeTimer) bool
func resetTimer(*runtimeTimer, int64) bool
func modTimer(t *runtimeTimer, when, period int64, f func(any, uintptr), arg any, seq uintptr)

// 计时器类型代表单个事件。
// 当计时器过期时，当前时间将通过C发送，
// 除非计时器是由AfterFunc创建的。
// 必须使用NewTimer或AfterFunc创建计时器。
type Timer struct {
	C <-chan Time
	r runtimeTimer
}

// 停止可防止计时器触发。
// 如果调用停止计时器，则返回true；如果计时器已过期或已停止，则返回false。
// Stop不会关闭通道，以防止后续通道的读取错误
// 。
// 
// 要确保在停止调用后通道为空，请检查
// 返回值并排空通道。
// 例如，假设程序尚未收到来自t.C的消息：
// 
// 如果！t、 Stop（）{
// /<-t.C 
// /}
// 
// 这不能与来自计时器
// 通道的其他接收或对计时器Stop方法的其他调用同时进行。
// 
// 对于使用AfterFunc（d，f）创建的计时器，如果t.Stop返回false，则计时器
// 已过期，且函数f已在其自身的goroutine中启动；
// Stop在返回之前不会等待f完成。
// 如果调用方需要知道f是否已完成，则必须明确地将
// 与f协调。
func (t *Timer) Stop() bool {
	if t.r.f == nil {
		panic("time: Stop called on uninitialized Timer")
	}
	return stopTimer(&t.r)
}

// NewTimer创建一个新的计时器，该计时器将在至少持续时间d之后发送
// 其通道上的当前时间。
func NewTimer(d Duration) *Timer {
	c := make(chan Time, 1)
	t := &Timer{
		C: c,
		r: runtimeTimer{
			when: when(d),
			f:    sendTime,
			arg:  c,
		},
	}
	startTimer(&t.r)
	return t
}

// 重置更改计时器，使其在持续时间d之后过期。
// 如果计时器已激活，则返回true；如果计时器已过期或已停止，则返回false。
// 
// 对于使用新计时器创建的计时器，应仅在
// 已停止或已过期且通道已耗尽的计时器上调用Reset。
// 
// 如果一个程序已经从t.C接收到一个值，那么已知的计时器
// 已经过期，通道已耗尽，因此可以直接使用t.Reset。
// 但是，如果程序尚未从t.C.接收到值，则必须停止计时器，如果停止，则报告计时器已过期
// 在停止之前，通道将显式排空：
// 
// 如果！t、 Stop（）{
// <-t.C 
// }
// t.Reset（d）
// 
// 这不应与来自计时器
// 通道的其他接收同时进行。
// 
// 请注意，不可能正确使用Reset的返回值，因为在耗尽通道和新计时器过期之间存在竞争条件。
// 如上所述，应始终在停止或过期的通道上调用重置。
// 返回值的存在是为了保持与现有程序的兼容性。
// 
// 对于使用AfterFunc（d，f）创建的计时器，重置或者重新安排
// 何时运行f，在这种情况下重置返回true，或者安排f 
// 再次运行，在这种情况下它返回false。
// 当Reset返回false时，Reset在返回前不等待前一个f到
// 完成，也不保证后续的
// 运行f的goroutine不会与前一个
// 同时运行。如果调用方需要知道
// f的先前执行是否已完成，则必须明确地与f协调。
func (t *Timer) Reset(d Duration) bool {
	if t.r.f == nil {
		panic("time: Reset called on uninitialized Timer")
	}
	w := when(d)
	return resetTimer(&t.r, w)
}

// sendTime在c.
func sendTime(c any, seq uintptr) {
	select {
	case c.(chan Time) <- Now():
	default:
	}
}

// After等待持续时间过去，然后在返回的通道上发送当前时间
// 。
// 它相当于NewTimer（d）。C.
// 在计时器启动之前，垃圾收集器不会恢复基础计时器
// 直到计时器启动。如果效率是一个问题，请使用NewTimer 
// 并调用Timer。如果不再需要计时器，请停止。
func After(d Duration) <-chan Time {
	return NewTimer(d).C
}

// AfterFunc等待持续时间过去，然后在自己的goroutine中调用f 
// 。它返回一个计时器，可以使用它的Stop方法取消调用。
func AfterFunc(d Duration, f func()) *Timer {
	t := &Timer{
		r: runtimeTimer{
			when: when(d),
			f:    goFunc,
			arg:  f,
		},
	}
	startTimer(&t.r)
	return t
}

func goFunc(arg any, seq uintptr) {
	go arg.(func())()
}
